/*
	Copyright 2009 Jason Nottingham

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.


    How to submit a patch:
    1. create or modify a test case (under 'tests') so that it fails to compile/link/run without 
       your change
    2. verify you have the latest sources (resync/merge)
    3. fix or add the missing functionality
    4. verify that your changes fixes the newly broken test case in #1 - it now builds and runs 
       C++ the same as the original C#
    5. create a Subversion-friendly diff or patch file of your changes (including the test cases)
    6. submit your patch at http://gonative.codeplex.com


*/

#pragma once

#pragma message("collections.h")
#include "BasicDataTypes.h"


/*
template <class T>
class Comparer
{
public:
	int Equals( T t1, T t2, COMPARER c )
	{
		return c ( t1, t2 );
	}
};
*/


// By default, GoNativeLib uses it's own small C++ class for implementing lists and dictionaries (maps).
// If you are working intensively with large lists or dictionaries, OR you expect to directly modify
// the generated C++ extensively (i.e. you used GoNative once to translate to C++ and C++ (not C#) is
// now your primary development language, you can uncomment the following #define to cause the GoNativeLib
// collection classes to inherit from the std c++ classes.
// In the case of the unit tests, this was observed to increase the number of times that string
// copy constructors were called when building a dictionary, but an appreciable performance hit was
// not observed.

// #define USE_STD_CPP



#ifdef USE_STD_CPP
#include <list>
#include <map>
#endif


template <class T>
#ifdef USE_STD_CPP
class List : public std::list<T>, object
#else
class List : object
#endif
{
private:
	// using a linked list initially.
	// idea: change to tree if list grows large
	// idea: use dynamic array if user specifies the max size of the list
	typedef struct list_item_a
	{
		T item;
        T *pItem;
		struct list_item_a *Next;
	} list_item;
	list_item *head, *tail, *iterator;

	list_item *next_item;
	int next_index;

	void Initialize()
	{ 
		head = tail = iterator = NULL; 
		next_item = NULL;
		next_index = -1;
		count = 0;
	}

	int count;

public:

	int	Count() { return count; }
	int	Length() { return count; }

	List()
	{
		Initialize();
		// printf( "%s this 0x0%x, head 0x0%x\n", __FUNCTION__, this, head );
		count = 0;
	}

	~List()
	{
		// printf( "%s this 0x0%x, head 0x0%x\n", __FUNCTION__, this, head );
		Clear();
	}

	List( List<T> &copy_from )
	{
		Initialize();
		for( int i = 0; i < copy_from.Count(); i++ )
			Add( copy_from[i] );
		// printf( "%s this 0x0%x, head 0x0%x\n", __FUNCTION__, this, head );
	}

	List( List<T> *copy_from )
	{
		Initialize();
		T t;
		copy_from->start_iteration();
		while( copy_from->get_next( t ) )
			Add( t );
		// printf( "%s this 0x0%x, head 0x0%x\n", __FUNCTION__, this, head );
	}

	DATATYPE GetDataType() const { return DATATYPE_LIST; };
	
	void Add( T *t )
	{
		list_item *new_entry = (list_item*)malloc(sizeof(list_item));
		if ( !new_entry )
			return;
		memset( new_entry, 0, sizeof(list_item) );
		new_entry->pItem = t;
		new_entry->Next = NULL;
		if ( head == NULL )
			head = tail = iterator = new_entry;
		else
		{
			tail->Next = new_entry;
			tail = new_entry;
		}
		// printf( "%s this 0x0%x, head 0x0%x, item 0x0%x\n", __FUNCTION__, this, head, new_entry );
		count++;
	}

	void Add( T t )
	{
		list_item *new_entry = (list_item*)malloc(sizeof(list_item));
		if ( !new_entry )
			return;
		memset( new_entry, 0, sizeof(list_item) );
		new_entry->item.copy_from(t);
		new_entry->Next = NULL;
		if ( head == NULL )
			head = tail = iterator = new_entry;
		else
		{
			tail->Next = new_entry;
			tail = new_entry;
		}
		// printf( "%s this 0x0%x, head 0x0%x, item 0x0%x\n", __FUNCTION__, this, head, new_entry );
		count++;
	}


	inline T operator+( T t )
	{
		Add( t );
		return t;
	}

	void Clear()
	{
		list_item *item = head;

		while( item ) 
		{
			// printf( "%s this 0x0%x, head 0x0%x, item 0x0%x\n", __FUNCTION__, this, head, item );
			list_item *to_delete = item;
			item = item->Next;
			free( to_delete );
		}
		head = tail = NULL;
		count = 0;
	}



	void start_iteration()
	{
		iterator = head;
		next_item = NULL;
		next_index = -1;
	}

	BOOL get_next( T &t )
	{
		if ( iterator )
		{
			t.copy_from( iterator->item );
			iterator = iterator->Next;
			return TRUE;
		}
		return FALSE;
	}

	T *get_next()
	{
		if ( iterator )
		{
            T *t = iterator->pItem;
			iterator = iterator->Next;
			return t;
		}
		return NULL;
	}

	inline T& operator[]( int index )
	{ 
		assert( index < (int)count );

		list_item *current;
		if ( index == next_index )
		{
			// we cached a pointer to the item they want
			current = next_item;
			next_index = index+1;
		}
		else
		{
			next_index = index+1;
			current = head;
			while( index-- )
				current = current->Next;
		}

		next_item = ( current ) ? current->Next : NULL;
		if ( next_item == NULL )
			next_index = -1;

		return current->item;
	}

	int Find( T *t )
	{ 
		list_item *current = head;
		int index = 0;
		while( index < count )
		{
			if ( T::compare( t, &current->item ) == 0 )
				return index;
			current = current->Next;
			index++;
		}
		return -1;
	}

};



#ifndef USE_STD_CPP

template <class Key,class Value>
class Dictionary : object
{
	// std::map generates alot of churn for object creation/destruction

	// just use a simple list for now, expand it to a tree later

private:
	List<Key>	keyList;
	List<Value>	valueList;
	int			itr;

public:

	Value& operator[]( Key key )
	{
		int i = keyList.Find( &key );
		if ( i == -1 )
		{
			i = keyList.Count();
			keyList.Add( key );
			Value *newValue = new Value();
			valueList.Add( *newValue );
		}
		assert( keyList.Count() == valueList.Count() );
		return valueList[i];
	}

	DATATYPE GetDataType() const { return DATATYPE_DICTIONARY; };

	void start_iteration()
	{
		assert( keyList.Count() == valueList.Count() );
		itr = 0;
	}

	BOOL get_next( Key &k, Value &v )
	{
		assert( keyList.Count() == valueList.Count() );
		if ( itr >= keyList.Count() )
			return FALSE;
		k.copy_from( keyList[itr] );
		v.copy_from( valueList[itr] );
		itr++;
		return TRUE;
	}

};


#else

template <class Key,class Value,class Comparer>
class Dictionary : public std::map<Key,Value,Comparer>, object
{
private:
	std::map<Key,Value,Comparer>::iterator	itr;

public:
	void start_iteration()
	{
		itr = begin();
	}
	
	BOOL get_next( Key* k, Value* v )
	{
		if ( itr == end() )
		{
			return FALSE;
		}
		*k = itr->first;
		*v = itr->second;
		itr++;
		return TRUE;
	}

	void end_iteration( Key* k, Value* v )
	{
	}

};

#endif

